package edu.csci3308.ekwhite.bigintegers;

import java.util.ArrayList;
import java.util.List;


public class BigInteger implements Comparable<BigInteger> {
	
	private List<Integer> digits;
	
	private boolean positive;
	
	public List<Integer> getDigits() {
		return digits;
	}
	
	public boolean isPositive() {
		return positive;
	}
	
	public void setDigits(List<Integer> digits) {
		this.digits = digits;
	}
	
	public void setPositive(boolean positive) {
		this.positive = positive;
	}
	
	
	public BigInteger sum(BigInteger addend)
	{
		BigInteger answer = new BigInteger();
		answer.digits.clear();
		answer.positive = true;
		Integer carry = 0;
		System.out.println("test");
		for (Integer i = 0; i < getDigits().size(); ++i)
		{
			Integer digit = digits.get(i) + carry;
			if (i < addend.getDigits().size())
				digit += addend.digits.get(i);
			if (digit > 9)
			{
				answer.digits.add(digit%10);
				carry = 1;
			}
			else
			{
				answer.digits.add(digit);
				carry = 0;
			}			
		}
		if (carry > 0)
			answer.digits.add(carry);
		return answer;
	}
	
	public BigInteger diff(BigInteger subtractand)
	{
		BigInteger answer = new BigInteger();
		answer.digits.clear();
		answer.positive = true;
		Integer borrow = 0;
		for (Integer i = 0; i < getDigits().size(); ++i)
		{
			Integer digit = digits.get(i) - borrow;
			if (i < subtractand.getDigits().size())
				digit -= subtractand.digits.get(i);
			if (digit < 0)
			{
				answer.digits.add(digit+10);
				borrow = 1;
			}
			else
			{
				answer.digits.add(digit);
				borrow = 0;
			}
			
		}
		
		answer.trim();
		return answer;
	}
	
	public BigInteger subtract(BigInteger subtractand)
	{
		BigInteger answer = new BigInteger();
		answer.digits.clear();
		BigInteger n1 = this;
		n1.setPositive(true);
		BigInteger n2 = subtractand;
		n2.setPositive(true);
		
		if (isPositive() != subtractand.isPositive())
		{
			if (n1.compareTo(n2) > 0)
			{
				answer = n1.sum(n2);
				if (!isPositive())
					answer.setPositive(false);
				else
					answer.setPositive(true);
			}
			else
			{
				answer = n2.sum(n1);
				if (!isPositive())
					answer.setPositive(true);
				else	
					answer.setPositive(false);
			}
		}
		else
		{
		
			if (n1.compareTo(n2) > 0)
			{
				answer = n1.diff(n2);
				if (!isPositive())
					answer.setPositive(false);
				else
					answer.setPositive(true);
			}	
			else
			{
				answer = n2.diff(n1);
				if (!isPositive())
					answer.setPositive(true);
				else
					answer.setPositive(false);
			}
		}

		return answer;
		
	}
	
	public BigInteger add(BigInteger addend)
	{
		BigInteger answer = new BigInteger();
		answer.digits.clear();
		BigInteger n1 = this;
		n1.setPositive(true);
		BigInteger n2 = addend;
		n2.setPositive(true);
		
		if (isPositive() == addend.isPositive())
		{
			if (n1.compareTo(n2) > 0)
				answer = n1.sum(n2);
			else
				answer = n2.sum(n1);
			
			if (!isPositive())
				answer.setPositive(false);
			else
				answer.setPositive(true);
		}
		else
		{
		
			if (n1.compareTo(n2) > 0)
			{
				answer = n1.diff(n2);
				if (!isPositive())
					answer.setPositive(false);
				else
					answer.setPositive(true);
			}	
			else
			{
				answer = n2.diff(n1);
				if (!isPositive())
					answer.setPositive(true);
				else
					answer.setPositive(false);
			}
		}

		return answer;
		
	}
	
	private void trim()
	{
		Integer i = getDigits().size() - 1;
		
		while (i > 0 && digits.get(i) == 0)
		{
			digits.remove(digits.size() - 1);	
			--i;
		}
	}
	
	public BigInteger()
	{
		digits = new ArrayList<Integer>();
		digits.add(0);
		positive = true;
	}
	
	public BigInteger(BigInteger source)
	{
		digits = new ArrayList<Integer>();
		digits.addAll(source.getDigits());
		positive = source.isPositive();
	}
	
	public BigInteger(Integer num)
	{
		digits = new ArrayList<Integer>();
		positive = true;
		if (num == 0)
		{
			digits.add(0);
			return;
		}
		if (num < 0)
		{
			positive = false;
			num *= -1;
		}
		while (num > 0)
		{
			digits.add(num%10);
			num /= 10;
		}	
	}
	
	public BigInteger(String s)
	{
		positive = true;
		digits = new ArrayList<Integer> ();
		Integer i = 0;

		if (s.charAt(i) == '+')
			++i;
		
		if (s.charAt(i) == '-')
		{
			++i;
			positive = false;
		}
		
		for (Integer q = s.length() - 1; q >= i; --q)
		{
			digits.add(Integer.parseInt(s.substring(q, q+1)));
		}
		
		
	}
	
	

	public int compareTo(BigInteger anotherBigInteger) throws ClassCastException
	{
		if (!(anotherBigInteger instanceof BigInteger))
			throw new ClassCastException("I was expecting a Big Integer object");
		Integer smaller = -1;
		Integer bigger = 1;
		Integer equal = 0;
		if (isPositive() && !anotherBigInteger.isPositive())
			return bigger;
		if (!isPositive() && anotherBigInteger.isPositive())
			return smaller;
		if (isPositive())
		{
			if (getDigits().size() > anotherBigInteger.getDigits().size())
				return bigger;
			if (getDigits().size() < anotherBigInteger.getDigits().size())
				return smaller;
			for (Integer i = getDigits().size()-1; i >= 0; --i)
			{
				if (getDigits().get(i) < anotherBigInteger.getDigits().get(i))
					return smaller;
				if (getDigits().get(i) > anotherBigInteger.getDigits().get(i))
					return bigger;
			}
			
			return equal;	
						
		}
		else
		{
			if (getDigits().size() < anotherBigInteger.getDigits().size())
				return smaller;
			if (getDigits().size() > anotherBigInteger.getDigits().size())
				return bigger;
			for (Integer i = getDigits().size()-1; i >= 0; --i)
			{
				if (getDigits().get(i) < anotherBigInteger.getDigits().get(i))
					return bigger;
				if (getDigits().get(i) > anotherBigInteger.getDigits().get(i))
					return smaller;
			}
			
			return equal;	
		}
	}

	public boolean equals(BigInteger anotherBigInteger)
	{
		if (getDigits().size() != anotherBigInteger.getDigits().size())
			return false;
		if (isPositive() != anotherBigInteger.isPositive())
			return false;
		for (Integer i = getDigits().size() - 1; i >= 0; --i)
		{
			if (getDigits().get(i) != anotherBigInteger.getDigits().get(i))
				return false;
		}
		return true;
	}
	
	public String toString()
	{
		String answer = "";
		if (!isPositive() )
			answer += '-';
		for (Integer i = getDigits().size() - 1; i >= 0; --i)
			answer += getDigits().get(i).toString();
		return answer;
	}
}
